using System.Collections;
using System.Runtime.CompilerServices;
using UnityEngine;

public class Game : MonoBehaviour
{
	public delegate void GameEventHandler();

	public delegate void CheckpointEventHandler(int checkPointNumber);

	private static Game instance;

	private static GameObject parentObject;

	public static GameState gameState = GameState.NoGame;

	public static GameState gameStatePrevious = GameState.NoGame;

	public static int currentLevelNumber = -1;

	public static string currentLevelName = string.Empty;

	public static GameMode currentGameMode = GameMode.Unknown;

	private static bool unloadResources;

	private static bool unloadResourcesLater;

	private static int unloadResourcesFrameCounter;

	private GameTimeKeeper gameTimeKeeper;

	[HideInInspector]
	private bool levelLoading;

	private bool gameStarted;

	private bool gameFinished;

	private bool willRespawn;

	private GameObject levelCurrent;

	private GameObject levelCurrentStart;

	private GameObject levelCurrentFinish;

	private BallBehaviour ball;

	private BallGiro ballGiro;

	private OrbitCamera orbitCamera;

	public static float levelTime
	{
		get
		{
			if (GetInstance() != null)
			{
				if ((bool)instance.gameTimeKeeper)
				{
					return instance.gameTimeKeeper.GetTimer();
				}
				return 0f;
			}
			return 0f;
		}
	}

	public static bool touchActive
	{
		get
		{
			return instance.ball.processTouch;
		}
		set
		{
			instance.ball.processTouch = value;
		}
	}

	public static bool dying
	{
		get
		{
			return instance.ball.dying;
		}
		set
		{
			instance.ball.dying = value;
		}
	}

	public static bool ballActive
	{
		get
		{
			return instance.ball.isActive;
		}
	}

	public static bool ballAirborne
	{
		get
		{
			return instance.ball.isAirborne;
		}
	}

	[method: MethodImpl(32)]
	public static event GameEventHandler GameStartEvent;

	[method: MethodImpl(32)]
	public static event GameEventHandler GameWillFinishEvent;

	[method: MethodImpl(32)]
	public static event GameEventHandler GameFinishEvent;

	[method: MethodImpl(32)]
	public static event GameEventHandler GameStateChangedEvent;

	[method: MethodImpl(32)]
	public static event GameEventHandler WillDieEvent;

	[method: MethodImpl(32)]
	public static event GameEventHandler WillRespawnEvent;

	[method: MethodImpl(32)]
	public static event CheckpointEventHandler CheckpointActivatedEvent;

	public static Game GetInstance()
	{
		if (!instance)
		{
			parentObject = GameObject.Find("_GAME_");
			if (parentObject != null)
			{
				instance = parentObject.GetComponent<Game>();
			}
		}
		return instance;
	}

	public static void FireGameStartEvent()
	{
		if (Game.GameStartEvent != null)
		{
			Game.GameStartEvent();
		}
	}

	public static void FireGameWillFinishEvent()
	{
		if (Game.GameWillFinishEvent != null)
		{
			Game.GameWillFinishEvent();
		}
	}

	public static void FireGameFinishEvent()
	{
		if (Game.GameFinishEvent != null)
		{
			Game.GameFinishEvent();
		}
	}

	public static void FireGameStateChangedEvent()
	{
		if (Game.GameStateChangedEvent != null)
		{
			Game.GameStateChangedEvent();
		}
	}

	public static void FireWillDieEvent()
	{
		if (Game.WillDieEvent != null)
		{
			Game.WillDieEvent();
		}
	}

	public static void FireWillRespawnEvent()
	{
		if (Game.WillRespawnEvent != null)
		{
			Game.WillRespawnEvent();
		}
	}

	public static void FireCheckpointActivatedEvent(int checkPointNumber)
	{
		if (Game.CheckpointActivatedEvent != null)
		{
			Game.CheckpointActivatedEvent(checkPointNumber);
		}
	}

	public static void SetGameState(GameState state)
	{
		Debug.Log(string.Concat(Time.frameCount, "### gameState change:  ", gameState, " -> ", state, "  levelNumber=", currentLevelNumber, "  gameMode=", currentGameMode));
		gameStatePrevious = gameState;
		gameState = state;
		FireGameStateChangedEvent();
	}

	public static void LoadLevel(int levelNumber)
	{
		if (GetInstance() != null)
		{
			string text = "LevelPrefabs";
			string text2 = "Level." + levelNumber.ToString().PadLeft(2, '0');
			string prefabPath = text + "/" + text2 + "/" + text2;
			instance.DoLoadLevel(prefabPath, levelNumber);
		}
	}

	public static void LoadLevel(string prefabPath, int levelNumber)
	{
		if (GetInstance() != null)
		{
			instance.DoLoadLevel(prefabPath, levelNumber);
		}
	}

	public static void UnloadLevel()
	{
		if (GetInstance() != null)
		{
			instance.DoUnloadLevel();
		}
	}

	public static void ResetLevel()
	{
		if (GetInstance() != null)
		{
			instance.DoResetLevel();
		}
	}

	public static bool IsLevelLoading()
	{
		if (GetInstance() != null)
		{
			return instance.levelLoading;
		}
		return false;
	}

	public static void Respawn(bool restart = false, float delay = 0f)
	{
		if (GetInstance() != null)
		{
			instance.DoRespawn(restart, delay);
		}
	}

	public static void CancelRespawn()
	{
		if (GetInstance() != null)
		{
			instance.DoCancelRespawn();
		}
	}

	public static void ContinueRespawn()
	{
		if (GetInstance() != null)
		{
			instance.DoContinueRespawn();
		}
	}

	public static void Pause()
	{
		if (GetInstance() != null)
		{
			instance.DoPause();
		}
	}

	public static void Unpause(bool restorePreviousState = true)
	{
		if (GetInstance() != null)
		{
			instance.DoUnpause(restorePreviousState);
		}
	}

	public static void StopBall()
	{
		if (GetInstance() != null)
		{
			instance.ball.StopMovement();
		}
	}

	public static void UnloadResources()
	{
		unloadResources = true;
	}

	public static void UnloadResourcesLater()
	{
		if (!unloadResourcesLater)
		{
			unloadResourcesLater = true;
			unloadResourcesFrameCounter = 0;
		}
	}

	private void Awake()
	{
		//Application.targetFrameRate = Globals.targetFramerate;
		QualitySettings.vSyncCount = 0;
	}

	private void Start()
	{
		gameTimeKeeper = GameTimeKeeper.GetInstance();
		ball = BallBehaviour.GetInstance();
		ballGiro = BallGiro.GetInstance();
		orbitCamera = OrbitCamera.GetInstance();
		BallBehaviour.BallWillDieEvent += OnBallWillDie;
		BallBehaviour.BallFirstMoveEvent += OnGameStart;
		LevelEnd.LevelEndEnterEvent += OnGameFinish;
		if (!Economy.hasInstance)
		{
			Invoke("DoStartLevel", 0.2f);
			Respawn(false, 0.2f);
		}
	}

	private void OnDestroy()
	{
		BallBehaviour.BallWillDieEvent -= OnBallWillDie;
		BallBehaviour.BallFirstMoveEvent -= OnGameStart;
		LevelEnd.LevelEndEnterEvent -= OnGameFinish;
	}

	private void LateUpdate()
	{
		if (unloadResourcesLater)
		{
			unloadResourcesFrameCounter++;
			if (unloadResourcesFrameCounter > 300)
			{
				StartCoroutine(UnloadResourcesCo());
				unloadResourcesLater = false;
				unloadResources = false;
			}
		}
		if (unloadResources)
		{
			StartCoroutine(UnloadResourcesCo());
			unloadResources = false;
		}
	}

	private IEnumerator UnloadResourcesCo()
	{
		yield return new WaitForEndOfFrame();
		Resources.UnloadUnusedAssets();
	}

	private void DoResetLevel()
	{
		EventManager.WorldReset();
		EventManager.AfterWorldReset();
		SetSpawnPointToLevelStart();
	}

	private void DoUnloadLevel()
	{
		if (!(levelCurrent == null))
		{
			ball.StopMovement();
			ball.SetToNeutralPosition();
			ballGiro.Hide();
			orbitCamera.Enable(false);
			gameTimeKeeper.ResetTimer();
			Object.Destroy(levelCurrent);
			SetGameState(GameState.NoGame);
			currentLevelNumber = -1;
			currentLevelName = string.Empty;
			currentGameMode = GameMode.Unknown;
			levelCurrent = null;
			gameStarted = false;
			gameFinished = false;
			willRespawn = false;
		}
	}

	private void DoLoadLevel(string prefabPath, int levelNumber = 0)
	{
		levelLoading = true;
		SetGameState(GameState.LevelLoading);
		StartCoroutine(LoadLevelCO(prefabPath, levelNumber));
	}

	private void DoStartLevel()
	{
		if (levelCurrent == null)
		{
			Debug.Log("Game -> DoStartLevel : levelCurrent = null, looking for current level ...");
			levelCurrent = GameObject.Find("LEVEL");
			levelCurrentStart = GetStartObject(levelCurrent);
			levelCurrentFinish = GetFinishObject(levelCurrent);
		}
		if (!(levelCurrent == null))
		{
			LevelController levelController = levelCurrent.GetComponent<LevelController>();
			if (levelController == null)
			{
				Debug.Log("Game -> DoStartLevel : levelController = null, creating LevelController component ...");
				levelController = levelCurrent.AddComponent<LevelController>();
			}
			levelController.StartLevel();
			SetGameState(GameState.LevelReady);
		}
	}

	private IEnumerator LoadLevelCO(string prefabPath, int levelNumber = 0)
	{
		yield return null;
		DoUnloadLevel();
		ResourceRequest request = Resources.LoadAsync(prefabPath);
		yield return request;
		if (request.asset != null)
		{
			currentLevelNumber = levelNumber;
			currentLevelName = request.asset.name;
			levelCurrent = Object.Instantiate(request.asset as GameObject) as GameObject;
			levelCurrent.name = "LEVEL " + currentLevelName;
			levelCurrentStart = GetStartObject(levelCurrent);
			levelCurrentFinish = GetFinishObject(levelCurrent);
			if (levelCurrentStart != null && levelCurrentFinish != null)
			{
				levelCurrent.transform.position = (levelCurrentStart.transform.position - levelCurrentFinish.transform.position) / 2f;
			}
			SetSpawnPointToLevelStart();
		}
		else
		{
			Debug.Log("ERROR : level " + levelNumber + " prefab not found at path: " + prefabPath);
		}
		yield return null;
		DoStartLevel();
		orbitCamera.Enable();
		levelLoading = false;
	}

	private void DoRespawn(bool restart = false, float delay = 0f)
	{
		willRespawn = true;
		if (delay == 0f)
		{
			DoRespawnInstant(restart);
		}
		else
		{
			StartCoroutine(DoRespawnDelayed(restart, delay));
		}
	}

	private IEnumerator DoRespawnDelayed(bool restart = false, float delay = 0f)
	{
		if (restart)
		{
			gameTimeKeeper.ResetTimer();
		}
		yield return new WaitForSeconds(delay);
		if (willRespawn)
		{
			DoRespawnInstant(restart);
		}
	}

	private void DoRespawnInstant(bool restart = false)
	{
		bool flag = restart;
		if (!flag && SpawnPoint.isLevelStart)
		{
			flag = true;
		}
		if (flag)
		{
			gameStarted = false;
			gameFinished = false;
			gameTimeKeeper.ResetTimer();
			SetSpawnPointToLevelStart();
			DoResetLevel();
		}
		if (gameState == GameState.LevelReady || gameState == GameState.NoGame)
		{
			SetGameState(GameState.SpawningForStart);
		}
		else if (flag)
		{
			SetGameState(GameState.SpawningForRestart);
		}
		else
		{
			SetGameState(GameState.SpawningForReset);
		}
		orbitCamera.CustomBehaviourWatchSpawnPoint();
		ballGiro.Hide();
		FireWillRespawnEvent();
		if (UserInterface.GetInstance() == null && willRespawn)
		{
			willRespawn = false;
			DoContinueRespawn();
		}
	}

	private void DoCancelRespawn()
	{
		willRespawn = false;
		DoPause(GameState.CanceledSpawn);
	}

	private void DoContinueRespawn()
	{
		if (gameState == GameState.CanceledSpawn)
		{
			DoUnpause();
		}
		willRespawn = false;
		float resumeDelay = ballGiro.Appear();
		ball.Reset(resumeDelay);
		orbitCamera.CustomBehaviourEndAll(1f);
		if (gameState == GameState.SpawningForStart || gameState == GameState.SpawningForRestart)
		{
			SetGameState(GameState.ReadyToStart);
		}
		else
		{
			SetGameState(GameState.ReadyToContinue);
		}
	}

	private void DoPause(GameState pauseState = GameState.Paused)
	{
		Time.timeScale = 0f;
		Time.fixedDeltaTime = Time.timeScale * 0.02f;
		if (gameStarted & !gameFinished)
		{
			gameTimeKeeper.StopTimer();
		}
		EventManager.GameFreeze();
		SetGameState(pauseState);
	}

	private void DoUnpause(bool restorePreviousState = true)
	{
		Time.timeScale = 1f;
		Time.fixedDeltaTime = Time.timeScale * 0.02f;
		if (gameStarted & !gameFinished)
		{
			gameTimeKeeper.StartTimer();
		}
		EventManager.GameUnfreeze();
		if (restorePreviousState)
		{
			SetGameState(gameStatePrevious);
		}
	}

	private void OnBallWillDie()
	{
		FireWillDieEvent();
		if (!Economy.hasInstance)
		{
			DoRespawn(false, 0f);
		}
	}

	private void OnGameStart()
	{
		if (!gameStarted)
		{
			gameStarted = true;
			gameTimeKeeper.StartTimer();
			FireGameStartEvent();
		}
		SetGameState(GameState.Playing);
	}

	private void OnGameFinish(GameObject levelEnd)
	{
		if (!gameFinished)
		{
			gameFinished = true;
			gameTimeKeeper.StopTimer();
			FireGameWillFinishEvent();
		}
		SetGameState(GameState.Finished);
	}

	private GameObject GetStartObject(GameObject level)
	{
		if (level == null)
		{
			return null;
		}
		Transform transform = level.transform.Find("Level Start");
		if (transform == null)
		{
			transform = level.transform.Find("Level Start Old");
		}
		if (transform != null)
		{
			return transform.gameObject;
		}
		return null;
	}

	private GameObject GetFinishObject(GameObject level)
	{
		if (level == null)
		{
			return null;
		}
		Transform transform = level.transform.Find("Level Finish");
		if (transform != null)
		{
			return transform.gameObject;
		}
		return null;
	}

	private void SetSpawnPointToLevelStart()
	{
		if (levelCurrentStart == null)
		{
			SpawnPoint.SetPosition(Vector3.zero, true);
			SpawnPoint.SetRotation(Quaternion.identity);
			return;
		}
		SpawnPoint.SetPosition(levelCurrentStart.transform.TransformPoint(Vector3.up * 0.5415f), true);
		if (levelCurrentStart.name == "Level Start Old")
		{
			SpawnPoint.SetPosition(levelCurrentStart.transform.TransformPoint(Vector3.up * 0.75f), true);
		}
		SpawnPoint.SetRotation(levelCurrentStart.transform.rotation);
	}
}
